package com.jhf.youke.base.domain.service;

import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.digest.DigestUtil;
import cn.hutool.json.JSONUtil;
import com.jhf.youke.base.domain.converter.DigitalSignatureConverter;
import com.jhf.youke.base.domain.exception.DigitalSignatureException;
import com.jhf.youke.base.domain.gateway.DigitalSignatureRepository;
import com.jhf.youke.base.domain.model.Do.DigitalSignatureDo;
import com.jhf.youke.base.domain.model.po.DigitalSignaturePo;
import com.jhf.youke.base.domain.model.vo.DigitalSignatureVo;
import com.jhf.youke.core.ddd.AbstractDomainService;
import com.jhf.youke.core.entity.PageQuery;
import com.jhf.youke.core.entity.Pagination;
import com.jhf.youke.core.utils.CacheUtils;
import com.jhf.youke.core.utils.RsaUtils;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.codec.binary.Base64;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.security.KeyPair;
import java.security.PrivateKey;
import java.util.List;
import java.util.Optional;
import java.util.UUID;


/**
 * @author RHJ
 */
@Service
@Log4j2
public class DigitalSignatureService extends AbstractDomainService<DigitalSignatureRepository, DigitalSignatureDo, DigitalSignatureVo> {


    @Resource
    DigitalSignatureConverter digitalSignatureConverter;

    @Override
    public boolean update(DigitalSignatureDo entity) {
        DigitalSignaturePo digitalSignaturePo = digitalSignatureConverter.do2Po(entity);
        return repository.update(digitalSignaturePo);
    }

    @Override
    public boolean updateBatch(List<DigitalSignatureDo> doList) {
        List<DigitalSignaturePo> poList = digitalSignatureConverter.do2PoList(doList);
        return repository.updateBatch(poList);
    }

    @Override
    public boolean delete(DigitalSignatureDo entity) {
        DigitalSignaturePo digitalSignaturePo = digitalSignatureConverter.do2Po(entity);
        return repository.delete(digitalSignaturePo);
    }

    @Override
    public boolean deleteBatch(List<Long> idList) {
        return repository.deleteBatch(idList);
    }

    @Override
    public boolean insert(DigitalSignatureDo entity) {
        DigitalSignaturePo digitalSignaturePo = digitalSignatureConverter.do2Po(entity);
        KeyPair pair = SecureUtil.generateKeyPair("RSA");
        // 将private 转为string
        digitalSignaturePo.setPrivateKey(Base64.encodeBase64String(pair.getPrivate().getEncoded()));
        digitalSignaturePo.setPublicKey(Base64.encodeBase64String(pair.getPublic().getEncoded()));
        digitalSignaturePo.setSalt(UUID.randomUUID().toString());
        digitalSignaturePo.preInsert();
        return repository.insert(digitalSignaturePo);
    }

    @Override
    public boolean insertBatch(List<DigitalSignatureDo> doList) {
        List<DigitalSignaturePo> poList = digitalSignatureConverter.do2PoList(doList);
        return repository.insertBatch(poList);
    }

    @Override
    public Optional<DigitalSignatureVo> findById(Long id) {
        Optional<DigitalSignaturePo> digitalSignaturePo =  repository.findById(id);
        DigitalSignatureVo digitalSignatureVo = digitalSignatureConverter.po2Vo(digitalSignaturePo.orElse(new DigitalSignaturePo()));
        return Optional.ofNullable(digitalSignatureVo);
        
    }

    @Override
    public boolean remove(Long id) {
        return repository.remove(id);
    }

    @Override
    public boolean removeBatch(List<Long> idList) {
        return repository.removeBatch(idList);
    }

    @Override
    public List<DigitalSignatureVo> findAllMatching(DigitalSignatureDo entity) {
        DigitalSignaturePo digitalSignaturePo = digitalSignatureConverter.do2Po(entity);
        List<DigitalSignaturePo>digitalSignaturePoList =  repository.findAllMatching(digitalSignaturePo);
        return digitalSignatureConverter.po2VoList(digitalSignaturePoList);
    }


    @Override
    public Pagination<DigitalSignatureVo> selectPage(DigitalSignatureDo entity){
        DigitalSignaturePo digitalSignaturePo = digitalSignatureConverter.do2Po(entity);
        PageQuery<DigitalSignaturePo> pageQuery = new PageQuery<>(digitalSignaturePo,entity.getCurrentPage(), entity.getPageSize(), entity.getQuerySort());
        Pagination<DigitalSignaturePo> pagination = repository.selectPage(pageQuery);
        return new Pagination<DigitalSignatureVo>(pagination.getPageNum(),pagination.getPageSize(),pagination.getTotalSize(),
                digitalSignatureConverter.po2VoList(pagination.getList()));
    }


    public String verification(String sign, String data, String nonceStr, Long companyId) throws Exception {
        // 获取RSA的公私匙
       DigitalSignatureDo digitalSignatureDo = getByCache(companyId);
       if(digitalSignatureDo == null){
           throw new DigitalSignatureException("当前参数错误，没有找到密匙");
       }

       // 验证密文
       String check = DigestUtil.md5Hex(data + nonceStr + companyId);
       if(!sign.equals(check)){
           throw new DigitalSignatureException("签名验证错误");
       }

       //解密
       PrivateKey privateKey = RsaUtils.getPrivateKey(digitalSignatureDo.getPrivateKey());

       String decrypt = RsaUtils.decrypt(data, privateKey);

        log.info("解密后 {}", decrypt);

        return decrypt;

    }


    public DigitalSignatureDo getByCache(Long companyId) throws Exception{
        String key = "digital_signature_" + companyId;
        DigitalSignatureDo digitalSignatureDo = CacheUtils.getObject(key, DigitalSignatureDo.class);
        if (digitalSignatureDo == null) {
            DigitalSignaturePo digitalSignaturePo = repository.getAllByCompanyId(companyId);
            digitalSignatureDo = digitalSignatureConverter.po2Do(digitalSignaturePo);
            if (digitalSignaturePo != null) {
                CacheUtils.set(key, JSONUtil.toJsonStr(digitalSignatureDo), 20 * 60 * 60);
            }
        }
        return digitalSignatureDo;
    }


    public Optional<DigitalSignatureVo> getByCompany(Long id)throws Exception {
        DigitalSignatureDo digitalSignatureDo =  getByCache(id);
        DigitalSignatureVo digitalSignatureVo = digitalSignatureConverter.do2Vo(digitalSignatureDo);
        return Optional.ofNullable(digitalSignatureVo);

    }

}

